#include "Compression.h"
#include <iostream>

using std::cout;

void LZW_bpp(HXLBMPFILE &src, const vector<bitset<16>> &encode_result)
{
	int i, j;
	int n = src.imageh * src.imagew;
	float p[256];
	int count_pixel[256] = {0};
	for (i = 0; i < src.imagew; i++) // 统计像素出现次数
		for (j = 0; j < src.imageh; j++)
		{
			count_pixel[src.pDataAt(i)[j]] += 1;
		}

	for (i = 0; i < 256; i++) // 计算像素出现频率
	{
		p[i] = (float)count_pixel[i] / (float)n;
	}

	float H = 0, L = 0; // 信源熵H和压缩后的L

	for (i = 1; i <= 256; i++)
	{
		if (p[i - 1] != 0)
			H += -((p[i - 1]) * (log(p[i - 1]) / log(2)));
	}
	cout << "信息熵H=" << H << '\n';

	int size = encode_result.size();
	float bit_data = size * 16;
	float avg_length = bit_data / (float)n;

	for (i = 0; i < 256; i++)
	{
		L += p[i] * avg_length;
	}

	cout << "L=" << L << "\n\n";
}

bool LZWEncode(HXLBMPFILE &src, const char *cFilename)
{
	LZW encode_lzw;

	string encode_data = "";
	string null = "";
	char c;
	int i, j;
	for (i = 0; i < src.imagew; i++)
		for (j = 0; j < src.imageh; j++)
		{
			null = "";
			c = src.pDataAt(i)[j];
			encode_data += null + c;
		}

	encode_lzw.encoding(encode_data);

	auto &encode_result = encode_lzw.get_encode_result();

	LZW_bpp(src, encode_result); // 计算压缩效率

	if (!writeHeader(src, cFilename))
	{
		cout << "bmp头部写入失败！\n";
		return false;
	}
	else
	{
		cout << "bmp头部写入成功！\n";
	}

	string result = ""; // 由于bitset直接写入文件是按照ASCII码，因此我们要调用writeBit才行

	for (auto it = encode_result.begin(); it != encode_result.end(); it++)
	{
		result += (*it).to_string();
	}

	if (!writeBit(result, cFilename))
	{
		cout << "像素数据写入异常！\n";
		return false;
	}
	else
	{
		cout << "像素数据写入成功！\n";
		return true;
	}
}

bool LZWDecode(HXLBMPFILE &des, const char *cFilename)
{
	LZW decode_lzw;

	if (!readHeader(des, cFilename)) // 首先读取头部
	{
		cout << "bmp头部读取失败！\n";
		return false;
	}
	else
		cout << "bmp头部读取成功\n";

	FILE *f;
	if ((f = fopen(cFilename, "r+b")) == NULL)
	{
		cout << "无法打开文件！\n";
		return false;
	}
	fseek(f, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD), SEEK_SET); //指向像素数据包

	char buffer;
	int flag;
	string read_string = "";
	while ((flag = fread(&buffer, sizeof(char), 1, f) != 0))
	{
		read_string += buffer; // 我们先将编码数据读入一个字符串
	}
	fclose(f);

	string::iterator it;
	string binary_data = "";
	for (it = read_string.begin(); it != read_string.end(); it++)
	{
		binary_data += Byte2Binary(*it); // 然后把每一位（char）转换成二进制，再合并成一个字符串
	}
	read_string.clear();

	int i, j = 15; // 这里j的取值需要根据bitset<>的大小决定
	string code = "";
	vector<bitset<16>> decode_data;
	for (i = 0; i < binary_data.size(); i++)
	{
		code += binary_data[i];
		j--;

		if (j < 0)
		{
			bitset<16> temp(code);
			decode_data.push_back(temp); // 把二进制组成的字符串，按位数转成bitset类型，构成待解码数据
			code = "";
			j = 15;
		}
	}
	binary_data.clear();

	decode_lzw.decoding(decode_data);

	string &decode_result = decode_lzw.get_decode_result();
	auto result_it = decode_result.begin();

	for (int i = 0; i < des.imagew; i++)
		for (int j = 0; j < des.imageh; j++)
		{
			des.pDataAt(i)[j] = *result_it; // 将像素值写入
			result_it++;
		}

	des.SaveBMPFILE("./output/result.bmp");
	return true;
}